﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;
using Syberia.Client.Extensions.Metacode;
using System.Collections;

namespace Syberia.Metacode
{
    public class ReflectionExplorableObject : ExplorableObject
    {
        Type otype;
        Object o;
        string readableName;
        ValueEditorWrapper wrapper;
        public ReflectionExplorableObject(object o, string name, ValueEditorWrapper ed)
        {
            otype = o.GetType();
            this.o = o;
            readableName = name;
            wrapper = ed;
        }
        public ReflectionExplorableObject(object o)
            : this(o, null, null)
        {

        }
        public override string Name
        {
            get
            {
                if (string.IsNullOrEmpty(readableName))
                {
                    return otype.Name;
                }
                else
                {
                    return readableName;
                }
            }
        }

        public override object EditableObject
        {
            get
            {
                return o;
            }
        }

        public override IEnumerable<ExplorableObject> SubObjects
        {
            get
            {
                if (wrapper != null)
                {
                    yield return wrapper;
                }

                MethodInfo[] m = otype.GetMethods(BindingFlags.Public | BindingFlags.NonPublic
                    | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy);

                yield return new ReflectedMethodList(m);

                PropertyInfo[] p = otype.GetProperties(BindingFlags.Public | BindingFlags.NonPublic
                    | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy);
                foreach (PropertyInfo pi in p)
                {
                    //yield return new FinalExplorableObject("[property] " + pi.Name);
                    ExplorableObject eo;
                    try
                    {
                        var vew = new ValueEditorWrapper(o, pi);
                        eo = new ReflectionExplorableObject(pi.GetValue(o, null), "[prop] " + pi.Name, vew);
                    }
                    catch (Exception exc)
                    {
                        eo = new FinalExplorableObject("[prop?] " + pi.Name, exc.ToString());
                    }
                    yield return eo;
                }

                if ((o as IEnumerable != null)) yield return new ReflectedIEnumerable(o as IEnumerable);

                FieldInfo[] f = otype.GetFields(BindingFlags.Public | BindingFlags.NonPublic
                    | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy);

                foreach (FieldInfo fi in f)
                {
                    ExplorableObject eo;
                    try
                    {
                        var vew = new ValueEditorWrapper(o, fi);
                        eo = new ReflectionExplorableObject(fi.GetValue(o), "[field] " + fi.Name, vew);
                    }
                    catch (Exception exc)
                    {
                        eo = new FinalExplorableObject("[field?] " + fi.Name, exc.ToString());
                    }
                    yield return eo;
                }

            }
        }
    }
}
